package com.freshcity.manager
{
	import com.freshcity.common.PopMsgBack;
	import com.freshcity.component.FLabel;
	import com.freshcity.core.GlobalVar;
	import com.freshcity.utils.StringUtil;
	import com.greensock.TweenLite;
	import com.pblabs.core.IPBManager;
	import com.pblabs.debug.Logger;
	
	import fl.controls.Label;
	
	import flash.errors.*;
	import flash.events.*;
	import flash.external.ExternalInterface;
	import flash.net.Socket;
	import flash.net.registerClassAlias;
	import flash.system.Security;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;

	public class CommunicatorManager implements IPBManager
	{
		[Inject]
		public var layerManager:LayerManager;		
		
		private static const retryTimes:int = 3;
		
		private var times:int = CommunicatorManager.retryTimes;
		
		private var sc:Socket;
		public var mailBox:Dictionary;

		private var connectCallBack:Function;
		private var connectFailedCallBack:Function;
		
		private var byteBuffer:ByteArray = new ByteArray(); //数据缓存
		private var dataLength:int; //接收到的数据长度
		private var headLen:int = 4; //数据包首部长度
		private var readFlag:Boolean;		
		private var connectCallBackPara:Array;
		private var popMessage:PopMsgBack;

		public function destroy():void
		{
		}

		public function initialize():void
		{
			sc=new Socket();
			mailBox=new Dictionary();
			sc.addEventListener(ProgressEvent.SOCKET_DATA, receivedHandler);
			sc.addEventListener(Event.CONNECT, onConnect);
			sc.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			sc.addEventListener(Event.CLOSE, onSocketClose);
			
			popMessage = new PopMsgBack();
			popMessage.submitBtn.addEventListener(MouseEvent.CLICK,onClosePopWin);

			ExternalInterface.addCallback('closeSocket', disconnect);
		}
		
		protected function onSocketClose(event:Event):void
		{
			showPopWin();
			Logger.error(this,"onSocketClose",event.toString());
		}
		
		private function onIOError(event:Event):void
		{
			showPopWin();
			Logger.error(this,"onIOError",event.toString());
		}
		
		public function disconnect():void
		{
			Logger.debug(this,"Try to disconnect socket...","");
			if(sc&&sc.connected){
				sc.close();
			}
		}

		/**
		 * ioErrorCallback: callback function if IOException occured when connect to socket server
		 * connectedCallback: callback function if connect to socket server successed.
		 */
		public function connect(ioErrorCallback:Function=null, connectedCallback:Function=null,para:Array=null):void
		{
			connectFailedCallBack=ioErrorCallback;
			connectCallBack=connectedCallback;
			connectCallBackPara=para;
			Security.loadPolicyFile('xmlsocket://' + GlobalVar.SOCKET_IP + ':' + GlobalVar.SOCKET_PORT);
			sc.connect(GlobalVar.SOCKET_IP, GlobalVar.SOCKET_PORT);
		}


		private function onSocketData(bytes:ByteArray):void
		{
			var opCode:int;
			var data:Object;
			var fun:Function;
			
				opCode=bytes.readShort();
				Logger.debug(this,"onSocketData","begin handle opCode:"+opCode);
				data=bytes.readObject();
				fun=mailBox[opCode];
				
				if (fun != null)
				{
					fun.call(null, data);
				}
		}
		
		/**
		 * 为避免一次接收到多条数据包，必须进行数据包的分离解码
		 * 网络数据解码
		 */
		private function receivedHandler(event:ProgressEvent):void
		{
			//开始读取数据的标记
			//每读取一条数据bytesAvailable值将随之减少
			//while (socket.bytesAvailable>=headLen) {
			while (sc.bytesAvailable)
			{
				if (!readFlag && sc.bytesAvailable >= headLen)
				{
					//读取数据长度
					dataLength=sc.readShort();
					readFlag=true;
				}
				//如果为0,表示收到异常消息，避免无限循环地等待
				if (dataLength == 0)
				{
					//dispatchEvent(new NetEvent(NetEvent.NULL_STREAM));
					return;
				}
				//数据流里的数据满足条件，开始读数据
				if (readFlag)
				{
					if (sc.bytesAvailable < dataLength)
					{
						dataLength=dataLength - sc.bytesAvailable;
						sc.readBytes(byteBuffer, byteBuffer.length, sc.bytesAvailable);
					}
					else
					{
						sc.readBytes(byteBuffer, byteBuffer.length, dataLength);
						byteBuffer.position = 0;
						onSocketData(byteBuffer);
						
						byteBuffer.clear();
						dataLength=0;
						readFlag=false;
					}
				}
			}
		}		

		public function onConnect(event:Event):void
		{
			//handler.onConnect(new Session(sc));
			if (connectCallBack != null)
			{
				connectCallBack.apply(null, connectCallBackPara);
			}
		}

		public function register(code:int, fun:Function):void
		{
			mailBox[code]=fun;
		}
		
		public function unRegister(code:int):void
		{
			delete mailBox[code]; 
		}		

		public function send(code:int, data:Object, callbackHandler:Function=null):void
		{
			Logger.debug(this,"send","it is request opCode:"+code);
			if (sc.connected)
			{
				times = CommunicatorManager.retryTimes;
				if (callbackHandler != null)
					mailBox[code]=callbackHandler;
				var bytes:ByteArray = new ByteArray();
				bytes.writeShort(code);
				bytes.writeObject(data);
				
				sc.writeShort(bytes.length);
				sc.writeBytes(bytes);
				
				sc.flush();
			}else if(times > 0){
				Logger.info(this,"Try to connect server times:",String(times));
				times--;
				TweenLite.delayedCall(0.2,connect,[null,send,[code,data,callbackHandler]]);
			}
			else
			{
				showPopWin();
			}
		}
		
		private function showPopWin():void
		{
			EffectManager.addUIMask([],0);
			LayerManager.highestLayer.addPopUp(popMessage,true);
		}
		
		protected function onClosePopWin(event:MouseEvent):void
		{
			ExternalInterface.call(" location.reload", true);
		}
	}
}
